using System;
using System.Collections;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using Sedna.Core.Controller.Configurations;
using Sedna.Core.Persistence;
using Spring.Util;

namespace Sedna.Core.Controller
{
    public class SingleSelectListController : ListController, ISingleSelectListController
    {
        private const String SELECTED_ITEM_KEY = "selectedItem";
        private const String SELECTED_VALUE_KEY = "selectedValue";

        private String selectedItemPath;

        # region Properties

        public virtual string SelectedItemPath
        {
            get { return selectedItemPath; }
            set { selectedItemPath = value; }
        }

        /// <summary>
        /// Make a sense only if <see cref="SelectedItemPath"/> is set
        /// otherwise always returns null
        /// </summary>
        public virtual object SelectedItem
        {
            get
            {
                if (!StringUtils.IsNullOrEmpty(SelectedItemPath))
                {
                    return GetObjectByPath(SelectedItemPath);
                }

                return null; /* ControllerContext[SELECTED_ITEM_KEY]; */
            }
            set
            {
                if (!StringUtils.IsNullOrEmpty(SelectedItemPath))
                {
                    SetObjectByPath(SelectedItemPath, value);
                }
                else
                {
                    // ControllerContext[SELECTED_ITEM_KEY] = value;
                }
            }
        }        
        
        # endregion

        private String SelectedValue
        {
            get
            {
                return ControllerContext[SELECTED_VALUE_KEY] as String;
            }
            set
            {
                ControllerContext[SELECTED_VALUE_KEY] = value;
            }
        }

        private bool IsEmptyElementSelected
        {
            get
            {
                if (Control is IConfigurationAware)
                {
                    IDropDownListConfiguration config =
                        (Control as IConfigurationAware).Configuration as IDropDownListConfiguration;

                    if (config != null && config.AddEmptyItem && config.EmptyItemValue == SelectedValue)
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        private bool IsNewElementSelected
        {
            get { return Control.SelectedValue != SelectedValue; }
        }

        private bool AddEmptyElement()
        {
            if (Control is IConfigurationAware)
            {
                IDropDownListConfiguration config =
                    (Control as IConfigurationAware).Configuration as IDropDownListConfiguration;

                if (config != null && config.AddEmptyItem)
                {
                    Control.Items.Insert(0, new ListItem(GetEmptyElementText, config.EmptyItemValue));

                    return true;
                }
            }

            return false;
        }
        
        private String GetEmptyElementText
        {
            get
            {
                IDropDownListConfiguration config =
                    (Control as IConfigurationAware).Configuration as IDropDownListConfiguration;

                String value = config.GetLocalizedPostfixLabel(config.EmptyItemTextKey, config.EmptyItemText);

                if (value == null)
                    value = config.EmptyItemText;
                
                return value;
            }
        }

        protected override void CustomBind(ICollection data)
        {            
            int index = 0;

            if (AddEmptyElement())
            {
                index = 1;

                if (!String.IsNullOrEmpty(SelectedItemPath) && SelectedItem == null)
                {
                    Control.Items[0].Selected = true;                    
                }
            }

            foreach (object obj in data)
            {
                ListItem item = Control.Items[index];

                ItemsCache.Add(item.Value, obj);

                if (!String.IsNullOrEmpty(SelectedItemPath))
                {
                    item.Selected = ElementsComparer.Equals(obj, SelectedItem);                    
                }

                index++;
            }
        }

        protected override void Control_AfterBinding(Control control)
        {
            SelectedValue = Control.SelectedValue;
        }

        protected override void Control_AfterUnbinding(Control control)
        {
            if (!controlBinded)
                return;

            controlBinded = false;

            AttachCacheToSession();

            if (!(Control as Control).Page.IsPostBack)
                return;

            SelectedValue = Control.SelectedValue;

            if (String.IsNullOrEmpty(SelectedItemPath))
            {
                return;
            }
            
            // It is useless to check if a new element selected
            // because anyway SelectedItem should be set            
            
            if (IsEmptyElementSelected)
            {
                // If data aren't cached we avoid unnecessary and untimely data loading
                SelectedItem = null;
                return;
            }

            if (!CacheData) // no caching
            {                                
                // not empty element selected

                // This data loading is untimely but necessary to get the object by selected value
                lastUsedDataProvider = (NewDataProvider != null) ? NewDataProvider : CurrentDataProvider;

                ICollection data = new ArrayList(lastUsedDataProvider.LoadData());

                Control.DataSource = data;
                Control.DataBind();

                int index = AddEmptyElement() ? 1 : 0;

                foreach (object obj in data)
                {
                    ListItem item = Control.Items[index];

                    if (item.Value == SelectedValue)
                    {
                        // This condition cannot be replaced by SelectedItem = ItemsCache[SelectedValue]; 
                        // after this cycle because ListItem should be selected

                        item.Selected = true;

                        // trying to aviod unnecessary rewriting
                        // it is useful if you use EqualsComparer and don't want 
                        // SelectedItem to be rewritten if they are equal by Equals() method
                        // but not equal by references
                        if (!ElementsComparer.Equals(obj, SelectedItem))
                        {
                            SelectedItem = obj;
                        }
                    }

                    ItemsCache.Add(item.Value, obj);

                    index++;
                }
            }
            else // data cached
            {
                // trying to aviod unnecessary rewriting
                // it is useful if you use EqualsComparer and don't want 
                // SelectedItem to be rewritten if they are equal by Equals() method
                // but not equal by references
                if (!ElementsComparer.Equals(ItemsCache[SelectedValue], SelectedItem))
                {
                    SelectedItem = ItemsCache[SelectedValue];
                }
            }
        }                        
    }
}
